package com.gitee.wsl.common.ui.draw.theme


import com.gitee.wsl.common.ui.base.Point
import com.gitee.wsl.common.ui.symbol.SampleBezierLine
import com.gitee.wsl.math.Math
import com.gitee.wsl.math.random.nextFloat
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
import kotlin.random.Random

/**
 * 实现 手绘 样式 分解
 * 引用  https://github.com/5A59/SketchyComponent
 */

object Sketchy {

    fun calcLine(startPoint: Point, endPoint: Point, step:Float=50f, brushWidth:Float=11f):List<SampleBezierLine>{
       val bezierList= mutableListOf<SampleBezierLine>()
        if (abs(startPoint.x - endPoint.x) < 0.00001) {
            parseVLine(startPoint,endPoint,bezierList,step, brushWidth)
        } else {
            parseLine(startPoint,endPoint,bezierList,step, brushWidth)
        }
        return bezierList
    }

    private fun parseVLine(startPoint: Point, endPoint: Point, bezierList: MutableList<SampleBezierLine>, step:Float, brushWidth:Float) {
        val x = startPoint.x
        var startY = min(startPoint.y, endPoint.y)
        val endY = max(endPoint.y, startPoint.y)

        var nextY: Float
        var controlX: Float
        var controlY: Float

        while (startY < endY) {
            nextY = min(startY + step * 2, endY)
            controlX = Random.nextFloat(x, x + brushWidth)
            controlY = Random.nextFloat(startY, nextY)
            val startPoint = Point(x, startY)
            var controlPoint = Point(controlX, controlY)
            val endPoint = Point(x, nextY)
            val bezier = SampleBezierLine(startPoint, controlPoint, endPoint)
            bezierList.add(bezier)

            controlX = Random.nextFloat(x - brushWidth, x)
            controlY = Random.nextFloat(startY, nextY)
            controlPoint = Point(controlX, controlY)
            bezierList.add(SampleBezierLine(startPoint, controlPoint, endPoint))
            startY += step
        }
    }

    private fun parseLine(startPoint: Point, endPoint: Point, bezierList: MutableList<SampleBezierLine>, step:Float, brushWidth:Float) {
        val k = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x)
        val b = (endPoint.x * startPoint.y - startPoint.x * endPoint.y) / (endPoint.x - startPoint.x)
        var startX = min(startPoint.x, endPoint.x)
        val endX = max(startPoint.x, endPoint.x)

        var nextX: Float
        var controlX: Float
        var controlY: Float

        while (startX < endX) {
            nextX = min(startX + step * 2, endX)
            controlX = Random.nextFloat(startX, nextX)
            controlY = Random.nextFloat(controlX * k + b, controlX * k + b + brushWidth)
            val startPoint = Point(startX, startX * k + b)
            var controlPoint = Point(controlX, controlY)
            val endPoint = Point(nextX, nextX * k + b)
            val bezier = SampleBezierLine(startPoint, controlPoint, endPoint)
            bezierList.add(bezier)

            controlX = Random.nextFloat(startX, nextX)
            controlY = Random.nextFloat(controlX * k + b - brushWidth, controlX * k + b)
            controlPoint = Point(controlX, controlY)
            bezierList.add(SampleBezierLine(startPoint, controlPoint, endPoint))
            startX += step
        }
    }

    fun calcSquare(startPoint: Point, width: Float = 0.0f, height: Float = 0.0f, step:Float=50f, brushWidth:Float=11f):List<SampleBezierLine>{
        val bezierList= mutableListOf<SampleBezierLine>()
        if (width <= 0.0 || height <= 0.0) {
            return bezierList
        }
        var lines = calcLine(startPoint, Point(startPoint.x + width, startPoint.y))
        bezierList.addAll(lines)

        lines = calcLine(
            Point(startPoint.x, startPoint.y + height),
            Point(startPoint.x + width, startPoint.y + height)
        )
        bezierList.addAll(lines)

        lines = calcLine(startPoint, Point(startPoint.x, startPoint.y + height))
        bezierList.addAll(lines)

        lines = calcLine(
            Point(startPoint.x + width, startPoint.y),
            Point(startPoint.x + width, startPoint.y + height)
        )
        bezierList.addAll(lines)

        return bezierList
    }

    fun calcSquareFill(startPoint: Point, width: Float = 0.0f, height: Float = 0.0f, step:Float=50f, brushWidth:Float=11f):List<SampleBezierLine>{
        val bezierList= mutableListOf<SampleBezierLine>()
        return bezierList
    }

    fun calcArc(center: Point,
                radius: Float = 0.0f,
                startAngle: Float = 0.0f,
                sweepAngle: Float = 0.0f,
                linkCenter: Boolean = true,
                step:Float=50f,
                brushWidth:Float=11f
    ):List<SampleBezierLine> {
        val bezierList = mutableListOf<SampleBezierLine>()
        if (radius <= 0) {
            return bezierList
        }
        var startX: Float
        var startY: Float

        var nextX: Float
        var nextY: Float
        var angle = startAngle
        var nextAngle: Float

        var startPoint = Point(0.0f, 0.0f)
        var endPoint = Point(0.0f, 0.0f)


        while (angle < (startAngle + sweepAngle)) {
            startX = Math.calcX(center.x, radius, angle)
            startY = Math.calcY(center.y, radius, angle)
            nextAngle = min(angle + step * 2, startAngle + sweepAngle)
            nextX = Math.calcX(center.x, radius, nextAngle)
            nextY = Math.calcY(center.y, radius, nextAngle)

            startPoint = Point(startX,startY)

            endPoint = Point(nextX, nextY)

            bezierList.addAll(calcLine(startPoint, endPoint,step, brushWidth))
            angle += step
        }

        if (linkCenter) {
            startX = Math.calcX(center.x, radius, startAngle)
            startY = Math.calcY(center.y, radius, startAngle)
            nextX = Math.calcX(center.x, radius, startAngle + sweepAngle)
            nextY = Math.calcY(center.y, radius, startAngle + sweepAngle)

            bezierList.addAll(
                calcLine(
                Point(center.x, center.y),
                Point(startX, startY),step, brushWidth)
            )
            bezierList.addAll(
                calcLine(
                Point(center.x, center.y),
                Point(nextX, nextY),step, brushWidth)
            )

        }

        return bezierList
    }

    /*fun calcArcFill(center: Point,
                radius: Float = 0.0f,
                startAngle: Float = 0.0f,
                sweepAngle: Float = 0.0f,
                linkCenter: Boolean = true,
                step:Float=50f,
                brushWidth:Float=11f
    ):List<SampleBezierLine> {
        val bezierList = mutableListOf<SampleBezierLine>()
        return bezierList
    }*/

    fun calcCircle(center: Point, radius: Float, step:Float=50f, brushWidth:Float=11f ):List<SampleBezierLine>{
        val bezierList = mutableListOf<SampleBezierLine>()

        if ( radius > 0) {
            bezierList.addAll(calcArc(center, radius,0f,360f,false,step, brushWidth))
        }

        return bezierList
    }


}